﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using Miado.Extensions;

namespace Miado
{
    /// <summary>
    /// This class serves as the manager for DB connections on a given 
    /// thread.  If a connection is already present for the given 
    /// connection string, it will provide the current DbConnection.
    /// Otherwise, it will create a new DbConnection.
    /// </summary>
    internal static class ConnectionManager
    {
        [ThreadStatic]
        private static IDictionary<string, DbConnection> _connections;

        /// <summary>
        /// Returns the current DbConnection on the current thread for 
        /// the given DB.
        /// </summary>
        /// <param name="db">The database for which to get the 
        /// connection string.</param>
        /// <returns>The current DbConnection for the given DB.</returns>
        internal static DbConnection CurrentConnectionFor(IDatabase db)
        {
            // cache connections on a single thread by connection string 
            if ( _connections == null )
            {
                _connections = new Dictionary<string, DbConnection>();
            }
            if ( !_connections.ContainsKey(db.ConnectionString) )
            {
                DbConnection conn = db.DbProviderFactory.CreateConnection();
                conn.ConnectionString = db.ConnectionString;
                _connections[db.ConnectionString] = conn;
            }

            DbConnection dbConn = _connections[db.ConnectionString];
            if ( dbConn.State != ConnectionState.Open )
            {
                dbConn.Open();
            }

            return dbConn;
        }

        /// <summary>
        /// Releases all the connections managed by this class.
        /// </summary>
        internal static void ReleaseConnections()
        {
            if ( _connections != null )
            {
                _connections.Values.Each(CloseConnection);
                _connections.Clear();
            }
        }

        /// <summary>
        /// Closes the connection.  Since there maybe multiple connections managed 
        /// by this class, we simply ignore any exceptions thrown during the 
        /// execution of the Close() method so as to not stop further connections
        /// from attempting to close.
        /// </summary>
        /// <param name="conn">The connection to close.</param>
        private static void CloseConnection(DbConnection conn)
        {
            try
            {
                if ( conn != null && conn.State == ConnectionState.Open )
                {
                    conn.Close();
                }
            }
            catch
            {
            }
        }
    }
}
